package com.cj.bus.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.util.*;


/**
 * 
 * @Description:
 * @Create 2014年12月18日下午9:08:24
 * @author yanghao
 */
@Service
@Order(Integer.MIN_VALUE)
public class SpringContextUtil implements ApplicationContextAware {

  private static ApplicationContext applicationContext;

  public static final String DEV_PROFILE = "dev";
  public static final String TEST_PROFILE = "test";
  public static final String PRO_PROFILE = "prod";
  
  public static final String PROJECT_SIGN = "BONC-FW-";

  /**
   * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量.
   */
  public void setApplicationContext(ApplicationContext applicationContext) {
    SpringContextUtil.applicationContext = applicationContext;
  }

  /**
   * 取得存储在静态变量中的ApplicationContext.
   */
  public static ApplicationContext getApplicationContext() {
    checkApplicationContext();
    return applicationContext;
  }

  public static <T> T getBean(Class<T> cls) {
    checkApplicationContext();
    return (T) applicationContext.getBean(cls);
  }
  
  @SuppressWarnings("unchecked")
  public static <T,A extends Annotation> Map<A,T> getBeansForAnnotationType(Class<T> cls, Class<A> annotationType) {
    checkApplicationContext();
    Map<String, T> map = applicationContext.getBeansOfType(cls);
    Assert.notEmpty(map, cls.getSimpleName() + "未在 spring初始化完成!");
    Map<A,T> result = new HashMap<>();
    for (String beanName : map.keySet()) {
      Annotation one = applicationContext.findAnnotationOnBean(beanName, annotationType);
        if (null != one) {
          result.put((A)one, map.get(beanName));
        }
    }
    return result;
  }
  
  public static <T> List<T> getBeans(Class<T> cls) {
    checkApplicationContext();
    Map<String, T> map = applicationContext.getBeansOfType(cls);
    Assert.notEmpty(map, cls.getSimpleName() + "未在 spring初始化完成!");
    List<T> list = new ArrayList<T>();
    for (T t : map.values()) {
      list.add(t);
    }
    return list;
  }


  /**
   * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
   */
  @SuppressWarnings("unchecked")
  public static <T> T getBean(String name) {
    checkApplicationContext();
    return (T) applicationContext.getBean(name);
  }

  @SuppressWarnings("unchecked")
  public static <T> T getBean(String name, String defaultName) {
    checkApplicationContext();
    Object bean = null;
    try {
      bean = applicationContext.getBean(name);
    } catch (NoSuchBeanDefinitionException e) {
      bean = applicationContext.getBean(defaultName);
    }
    return (T) bean;
  }

  private static void checkApplicationContext() {
    if (applicationContext == null) {
      throw new IllegalStateException(
          "applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
    }
  }

  // 国际化使用
  public static String getMessage(String key) {
    return applicationContext.getMessage(key, null, Locale.getDefault());
  }

  // 获取当前环境
  public static String getActiveProfile() {
    return applicationContext.getEnvironment().getActiveProfiles()[0];
  }

  //是否为线上环境
  public static  boolean isProd(){
    String currentProd = getActiveProfile();
    return StringUtils.isNotBlank(currentProd) && currentProd.equalsIgnoreCase(PRO_PROFILE);
  }

  public static  boolean isTest(){
    String currentProd = getActiveProfile();
    return StringUtils.isNotBlank(currentProd) && currentProd.equalsIgnoreCase(TEST_PROFILE);
  }

  public static String getProperty(String key) {
    return applicationContext.getEnvironment().getProperty(key);
  }

  public static <T>  T getProperty(String key,Class<T> targetType) {
    return applicationContext.getEnvironment().getProperty(key,targetType);
  }

  public static  boolean isOpenHdfs(){
    String openHdfs = getProperty("open.hdfs");
    return StringUtils.isNotBlank(openHdfs) && Boolean.valueOf(openHdfs) && isProd();
  }

}
